package io.github.iogogogo.commons.util;

import com.google.common.collect.Lists;
import io.vavr.Tuple;
import io.vavr.Tuple3;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.support.CronExpression;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Objects;

/**
 * Created by tao.zeng on 2024/11/7.
 */
@Slf4j
public class CronUtils {

    /**
     * Nearby local date time.
     * <p>
     * 获取cron当前次执行时间和前后次执行时间
     * <p>
     * String cron = "0 0/2 * * * ?";
     *
     * @param cron the cron
     * @return local date time
     */
    public static Tuple3<LocalDateTime, LocalDateTime, LocalDateTime> nearby(String cron) {
        // 转换成cron表达式
        CronExpression cronExpression = CronExpression.parse(cron);
        // 下一次执行时间
        LocalDateTime next = cronExpression.next(LocalDateTime.now());

        Objects.requireNonNull(next);

        // 两次间隔时间
        long between = Duration.between(next, cronExpression.next(next)).getSeconds();

        // 当前次执行时间
        LocalDateTime current = next.minusSeconds(between);

        // 上一次执行时间
        LocalDateTime previous = current.minusSeconds(between);

        log.info("now:{} previous:{} current:{} next:{}", DateTimeUtils.nowDateTime(), previous, current, next);

        return Tuple.of(previous, current, next);
    }

    /**
     * Nearby list.
     * <p>
     * 按照count获取最近几次执行时间
     *
     * @param cron    the cron
     * @param isAfter the is after
     * @param count   the count
     * @return the list
     */
    public static List<LocalDateTime> nearby(String cron, boolean isAfter, int count) {
        // 转换成cron表达式
        CronExpression cronExpression = CronExpression.parse(cron);
        // 下一次预计执行时间
        LocalDateTime nextFirst = cronExpression.next(LocalDateTime.now());

        Objects.requireNonNull(nextFirst);
        // 下下次预计执行时间
        LocalDateTime nextSecond = cronExpression.next(nextFirst);
        // 两次执行间隔
        long between = ChronoUnit.SECONDS.between(nextFirst, nextSecond);

        List<LocalDateTime> dateTimes = Lists.newArrayList();
        int i = 0;
        while (i++ < count) {
            Objects.requireNonNull(nextSecond);
            nextFirst = isAfter ? nextFirst.plusSeconds(between) : nextFirst.minusSeconds(between);
            dateTimes.add(nextFirst);
        }
        return dateTimes;
    }
}
